package logic

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	"mall/common/enumx"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/service/blog/rpc/blogclient"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/types/forum"
	"mall/service/user/rpc/userclient"

	log "github.com/sirupsen/logrus"
	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type MediaInfo struct {
	Uid       int64  `json:"uid"`
	Id        int64  `json:"id"`
	Url       string `json:"url"`
	Thumbnail bool   `json:"thumbnail"`
	Order     int32  `json:"order"`
}

type AuthorInfo struct {
	Id       int64  `json:"id"`
	Nickname string `json:"nickname"`
	Avatar   string `json:"avatar"`
	Level    int32  `json:"level"`
}

type PerfumeInfo struct {
	Id    int64          `json:"id"`
	Title string         `json:"title"`
	Slug  string         `json:"slug"`
	Media []*MediaInfo   `json:"media,omitempty"`
	Brand []*PerfumeInfo `json:"brand,omitempty"`
	Year  string         `json:"year,omitempty"`
}

type PostInfo struct {
	Id         int64        `json:"id"`
	ParentId   int64        `json:"parentId,omitempty"`
	Parent     *PerfumeInfo `json:"parent,omitempty"`
	Photos     []*MediaInfo `json:"photos,omitempty"`
	Grade      string       `json:"grade,omitempty"`
	StatusText string       `json:"statusText,omitempty"`
}

type TopicInfo struct {
	Id          int64      `json:"id"`
	Title       string     `json:"title,omitempty"`
	Slug        string     `json:"slug,omitempty"`
	ContentHtml string     `json:"contentHtml,omitempty"`
	StatusText  string     `json:"statusText,omitempty"`
	UpdatedAt   string     `json:"updatedAt"`
	Topic       *TopicInfo `json:"topic,omitempty"`
	ReplyCount  int32      `json:"replyCount"`
}

type PhotoInfo struct {
	Id         int64        `json:"id"` // 编号
	ParentId   int64        `json:"parentId,omitempty"`
	Parent     *PerfumeInfo `json:"parent,omitempty"` // 香水
	Photos     []*MediaInfo `json:"photos,omitempty"`
	StatusText string       `json:"statusText,omitempty"`
}

type DiagnoseLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewDiagnoseLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DiagnoseLogic {
	return &DiagnoseLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *DiagnoseLogic) Diagnose(in *forum.DiagnoseReq) (*forum.DiagnoseResp, error) {
	var count int
	var err error
	switch in.Diagnose {
	case 1: // 分析图片是否为残留记录（涉及到删除 分页要倒序，从最大值开始）
		count, err = l.diagnoseAttachment(in)
	case 2: // 分析图片有效性
		count, err = l.diagnoseAttachmentUrl(in)
	case 3: // 分析 forum_posts
		count, err = l.diagnoseUserReview(in)
	case 4: // 分析 forum_topics
		count, err = l.diagnoseUserAskedQuestion(in)
	case 5: // 分析 forum_topics
		count, err = l.diagnoseUserAnsweredQuestion(in)
	case 6: // 分析 forum_posts
		count, err = l.diagnoseUserPhoto(in)
	case 7: // 分析 forum_feeds
		count, err = l.diagnoseForumFeed(in)
	case 8: // 分析 forum_user_collects
		count, err = l.diagnoseUserCollect(in)
	}

	if err != nil {
		return nil, err
	}

	return &forum.DiagnoseResp{
		Total: int64(count),
	}, nil
}

func (l *DiagnoseLogic) diagnoseAttachment(in *forum.DiagnoseReq) (count int, err error) {
	return
}

func (l *DiagnoseLogic) diagnoseAttachmentUrl(in *forum.DiagnoseReq) (count int, err error) {
	return
}

func (l *DiagnoseLogic) diagnoseUserReview(in *forum.DiagnoseReq) (int, error) {
	filterMap := make(map[string]map[string][]any)
	filterMap[model.ForumPostColumns.PostAuthorID] = map[string][]any{
		"equalTo": []any{in.UserId},
	}
	filterMap[model.ForumPostColumns.ForumID] = map[string][]any{
		"equalTo": []any{l.svcCtx.Config.Query.PostForumId},
	}
	filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
		"notEqualTo": []any{enumx.ObjectStatusDeleted},
	}
	var pageSize int64 = 2
	selectCols := []string{
		model.ForumPostColumns.PostID,
		model.ForumPostColumns.ParentID,
		model.ForumPostColumns.PostStatus,
	}
	postList, count, err := l.svcCtx.ForumPost.GetList(l.ctx, model.M{
		"pageSize": pageSize,
		"orderBy":  model.ForumPostColumns.PostModifiedDate + " DESC",
		"select":   strings.Join(selectCols, ","),
	}, 1, filterMap)
	if err != nil {
		return 0, err
	}

	if len(postList) > 0 {
		var ids []any // []model.ForumPost.PostID
		var pids []string
		for _, post := range postList {
			ids = append(ids, post.PostID)
			pids = append(pids, strconv.FormatInt(int64(post.ParentID), 10))
		}

		metaFilterMap := make(map[string]map[string][]any)
		metaFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
			"in": ids,
		}
		metaFilterMap[model.ForumPostMetumColumns.MetaKey] = map[string][]any{
			"equalTo": []any{"_grade"},
		}
		metaList, _, listErr := l.svcCtx.ForumPost.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
		if listErr != nil {
			return 0, listErr
		}

		idGradeMap := make(map[uint64][]*forum.ForumMeta)
		if len(metaList) > 0 {
			metaKeys := make([]any, 0) // 二次查询的metaKey
			metaMap := make(map[string]string)
			for _, metum := range metaList {
				key := metum.MetaKey
				if key != "" && metum.MetaValue.Valid {
					val := metum.MetaValue.String
					if key == "_grade" {
						metaKeys = append(metaKeys, val)
						metaMap[val] = "_grade"
					}
				}
			}

			if len(metaKeys) > 0 { // 二次查询
				metaFilterMap = make(map[string]map[string][]any)
				metaFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
					"in": ids,
				}
				metaFilterMap[model.ForumPostMetumColumns.MetaKey] = map[string][]any{
					"in": metaKeys,
				}
				metaList, _, listErr = l.svcCtx.ForumPost.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
				if listErr != nil {
					return 0, listErr
				}

				if len(metaList) > 0 {
					for _, metum := range metaList {
						key := metum.MetaKey
						if key != "" && metum.MetaValue.Valid {
							if prefix, hasPrefix := metaMap[metum.MetaKey]; hasPrefix {
								if prefix == "_grade" {
									idGradeMap[metum.PostID] = append(idGradeMap[metum.PostID], &forum.ForumMeta{
										Id:    int64(metum.MetaID),
										Key:   key,
										Value: metum.MetaValue.String,
									})
								}
							}
						}
					}
				}
			}
		}

		perfumeMap, perfumeErr := l.getPerfumeMap(pids)
		if perfumeErr != nil {
			return 0, perfumeErr
		}

		var list []*PostInfo
		for _, post := range postList {
			var grade float64
			if ms, exist := idGradeMap[post.PostID]; exist {
				var gradeTotal int64 // 总评分
				var gradeCount int32 // 评分项数
				for _, m := range ms {
					if i, intErr := strconv.ParseInt(m.Value, 10, 32); intErr == nil {
						gradeTotal += i
						gradeCount += 1
					}
				}
				if gradeCount > 0 {
					grade = float64(gradeTotal) / float64(gradeCount)
				}
			}
			var parent *PerfumeInfo
			if perfumeMap != nil {
				if p, exist := perfumeMap[int64(post.ParentID)]; exist {
					parent = p
				}
			}

			list = append(list, &PostInfo{
				Id:         int64(post.PostID),
				ParentId:   int64(post.ParentID),
				Parent:     parent,
				Grade:      moneyx.FormatStar(grade, 1),
				StatusText: getStatusText(int32(post.PostStatus)),
			})
		}

		reviewItems, err := json.Marshal(list)
		if err != nil {
			log.Info(fmt.Sprintf("reviewItems marshal err: %+v", err))
			return 0, err
		}

		var meta []*userclient.UserMeta
		meta = append(meta, &userclient.UserMeta{
			Id:    in.UserId,
			Key:   mqueuex.UserStatisticForumReviewCount, // _review_count
			Value: strconv.FormatInt(count, 10),
		})
		meta = append(meta, &userclient.UserMeta{
			Id:    in.UserId,
			Key:   mqueuex.UserCacheForumReview, // _review_items
			Value: string(reviewItems),
		})
		_, err = l.svcCtx.UserRpc.BackendSetMemberMeta(l.ctx, &userclient.BackendSetMemberMetaReq{
			UserMeta: meta,
		})
		if err != nil {
			return 0, err
		}

		return int(count), nil
	}

	return 0, nil
}

func (l *DiagnoseLogic) diagnoseUserAskedQuestion(in *forum.DiagnoseReq) (int, error) {
	filterMap := make(map[string]map[string][]any)
	filterMap[model.ForumTopicColumns.TopicAuthorID] = map[string][]any{
		"equalTo": []any{in.UserId},
	}
	filterMap[model.ForumTopicColumns.ForumID] = map[string][]any{
		"moreThanOrEqualTo": []any{l.svcCtx.Config.Query.DefaultForumId},
	}
	filterMap[model.ForumTopicColumns.TopicStatus] = map[string][]any{
		"notEqualTo": []any{enumx.ObjectStatusDeleted},
	}

	var pageSize int64 = 3
	selectCols := []string{
		model.ForumTopicColumns.TopicID,
		model.ForumTopicColumns.Title,
		model.ForumTopicColumns.TopicModifiedDate,
		model.ForumTopicColumns.TopicStatus,
	}
	topicList, count, err := l.svcCtx.ForumTopic.GetList(l.ctx, model.M{
		"pageSize": pageSize,
		"orderBy":  model.ForumTopicColumns.TopicModifiedDate + " DESC",
		"select":   strings.Join(selectCols, ","),
	}, 1, filterMap)
	if err != nil {
		return 0, err
	}

	if len(topicList) > 0 {
		var ids []any // []model.ForumTopic.TopicID
		for _, topic := range topicList {
			ids = append(ids, topic.TopicID)
		}

		metaFilterMap := make(map[string]map[string][]any)
		metaFilterMap[model.ForumTopicMetumColumns.TopicID] = map[string][]any{
			"in": ids,
		}
		metaFilterMap[model.ForumTopicMetumColumns.MetaKey] = map[string][]any{
			"equalTo": []any{"_reply_count"},
		}
		metaList, _, listErr := l.svcCtx.ForumTopic.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
		if listErr != nil {
			return 0, listErr
		}

		idCountMap := make(map[uint64]int32)
		if len(metaList) > 0 {
			for _, metum := range metaList {
				if metum.MetaKey != "" && metum.MetaValue.Valid {
					if i, intErr := strconv.ParseInt(metum.MetaValue.String, 10, 32); intErr == nil {
						idCountMap[metum.TopicID] = int32(i)
					}
				}
			}
		}

		var list []*TopicInfo
		for _, topic := range topicList {
			var replyCount int32
			if cnt, exist := idCountMap[topic.TopicID]; exist {
				replyCount = cnt
			}

			list = append(list, &TopicInfo{
				Id:         int64(topic.TopicID),
				Title:      topic.Title,
				StatusText: getStatusText(int32(topic.TopicStatus)),
				UpdatedAt:  modelx.FormatTime(topic.TopicModifiedDate, ""),
				ReplyCount: replyCount,
			})
		}

		var meta []*userclient.UserMeta
		meta = append(meta, &userclient.UserMeta{
			Key:   mqueuex.UserStatisticForumQuestionCount, // _asked_question_count
			Value: strconv.FormatInt(count, 10),
		})
		askedQuestionItems, err := json.Marshal(list)
		if err != nil {
			log.Info(fmt.Sprintf("askedQuestionItems marshal err: %+v", err))
			return 0, err
		}

		meta = append(meta, &userclient.UserMeta{
			Id:    in.UserId,
			Key:   mqueuex.UserCacheForumQuestion, // _asked_question_items
			Value: string(askedQuestionItems),
		})
		_, err = l.svcCtx.UserRpc.BackendSetMemberMeta(l.ctx, &userclient.BackendSetMemberMetaReq{
			UserMeta: meta,
		})
		if err != nil {
			return 0, err
		}

		return int(count), nil
	}

	return 0, nil
}

func (l *DiagnoseLogic) diagnoseUserAnsweredQuestion(in *forum.DiagnoseReq) (int, error) {
	filterMap := make(map[string]map[string][]any)
	filterMap[model.ForumPostColumns.PostAuthorID] = map[string][]any{
		"equalTo": []any{in.UserId},
	}
	filterMap[model.ForumPostColumns.ForumID] = map[string][]any{
		"moreThanOrEqualTo": []any{l.svcCtx.Config.Query.DefaultForumId},
	}
	filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
		"notEqualTo": []any{enumx.ObjectStatusDeleted},
	}
	var pageSize int64 = 3
	selectCols := []string{
		model.ForumPostColumns.PostID,
		model.ForumPostColumns.TopicID,
		model.ForumPostColumns.PostContent,
		model.ForumPostColumns.PostModifiedDate,
		model.ForumPostColumns.PostStatus,
	}
	postList, count, err := l.svcCtx.ForumPost.GetList(l.ctx, model.M{
		"pageSize": pageSize,
		"orderBy":  model.ForumPostColumns.PostModifiedDate + " DESC",
		"select":   strings.Join(selectCols, ","),
	}, 1, filterMap)
	if err != nil {
		return 0, err
	}

	if len(postList) > 0 {
		var tids []any
		for _, post := range postList {
			tids = append(tids, post.TopicID)
		}

		topicFilterMap := make(map[string]map[string][]any)
		topicFilterMap[model.ForumTopicColumns.TopicID] = map[string][]any{
			"in": tids,
		}
		topicFilterMap[model.ForumTopicColumns.ForumID] = map[string][]any{
			"moreThanOrEqualTo": []any{l.svcCtx.Config.Query.DefaultForumId},
		}
		topicFilterMap[model.ForumTopicColumns.TopicStatus] = map[string][]any{
			"equalTo": []any{enumx.ObjectStatusAproved},
		}

		topicSelectCols := []string{
			model.ForumTopicColumns.TopicID,
			model.ForumTopicColumns.TopicAuthorID,
			model.ForumTopicColumns.Title,
		}
		topicList, _, listErr := l.svcCtx.ForumTopic.GetList(l.ctx, model.M{
			"select": strings.Join(topicSelectCols, ","),
		}, -1, topicFilterMap)
		if listErr != nil {
			return 0, listErr
		}

		idTopicMap := make(map[uint64]*model.ForumTopic)
		if len(topicList) > 0 {
			for _, topic := range topicList {
				idTopicMap[topic.TopicID] = topic
			}
		}

		metaFilterMap := make(map[string]map[string][]any)
		metaFilterMap[model.ForumTopicMetumColumns.TopicID] = map[string][]any{
			"in": tids,
		}
		metaFilterMap[model.ForumTopicMetumColumns.MetaKey] = map[string][]any{
			"equalTo": []any{"_reply_count"},
		}
		metaList, _, listErr := l.svcCtx.ForumTopic.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
		if listErr != nil {
			return 0, listErr
		}

		idCountMap := make(map[uint64]int32)
		if len(metaList) > 0 {
			for _, metum := range metaList {
				if metum.MetaKey != "" && metum.MetaValue.Valid {
					if i, intErr := strconv.ParseInt(metum.MetaValue.String, 10, 32); intErr == nil {
						idCountMap[metum.TopicID] = int32(i)
					}
				}
			}
		}

		var list []*TopicInfo
		for _, post := range postList {
			var topic *TopicInfo
			var replyCount int32
			if t, exist := idTopicMap[post.TopicID]; exist {
				if cnt, exist := idCountMap[t.TopicID]; exist {
					replyCount = cnt
				}
				topic = &TopicInfo{
					Id:         int64(t.TopicID),
					Title:      t.Title,
					ReplyCount: replyCount,
				}
			}
			list = append(list, &TopicInfo{
				Id:          int64(post.PostID),
				ContentHtml: post.PostContent,
				StatusText:  getStatusText(int32(post.PostStatus)),
				UpdatedAt:   modelx.FormatTime(post.PostModifiedDate, ""),
				Topic:       topic,
			})
		}

		var meta []*userclient.UserMeta
		meta = append(meta, &userclient.UserMeta{
			Key:   mqueuex.UserStatisticForumAnswerCount, // _answered_question_count
			Value: strconv.FormatInt(count, 10),
		})
		answeredQuestionItems, err := json.Marshal(list)
		if err != nil {
			log.Info(fmt.Sprintf("answeredQuestionItems marshal err: %+v", err))
			return 0, err
		}

		meta = append(meta, &userclient.UserMeta{
			Id:    in.UserId,
			Key:   mqueuex.UserCacheForumAnswer, // _answered_question_items
			Value: string(answeredQuestionItems),
		})
		_, err = l.svcCtx.UserRpc.BackendSetMemberMeta(l.ctx, &userclient.BackendSetMemberMetaReq{
			UserMeta: meta,
		})
		if err != nil {
			return 0, err
		}

		return int(count), nil
	}

	return 0, nil
}

func (l *DiagnoseLogic) diagnoseUserPhoto(in *forum.DiagnoseReq) (int, error) {
	filterMap := make(map[string]map[string][]any)
	filterMap[model.ForumPostColumns.PostAuthorID] = map[string][]any{
		"equalTo": []any{in.UserId},
	}
	filterMap[model.ForumPostColumns.ForumID] = map[string][]any{
		"equalTo": []any{l.svcCtx.Config.Query.PhotoForumId},
	}
	filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
		"notEqualTo": []any{enumx.ObjectStatusDeleted},
	}
	var pageSize int64 = 3
	selectCols := []string{
		model.ForumPostColumns.PostID,
		model.ForumPostColumns.ParentID,
	}
	postList, count, err := l.svcCtx.ForumPost.GetList(l.ctx, model.M{
		"pageSize": pageSize,
		"orderBy":  model.ForumPostColumns.PostModifiedDate + " DESC",
		"select":   strings.Join(selectCols, ","),
	}, 1, filterMap)
	if err != nil {
		return 0, err
	}

	if len(postList) > 0 {
		var ids []any // []model.ForumPost.PostID
		var pids []string
		for _, post := range postList {
			ids = append(ids, post.PostID)
			pids = append(pids, strconv.FormatInt(int64(post.ParentID), 10))
		}

		mediaFilterMap := make(map[string]map[string][]any)
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"in": ids,
		}
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": []any{enumx.ObjectTypePost},
		}
		pageSize = 8
		subSelectCols := []string{
			model.ForumAttachmentRelationshipColumns.AttachmentRelationshipID,
			model.ForumAttachmentRelationshipColumns.ObjectID,
			model.ForumAttachmentRelationshipColumns.AttachmentID,
			model.ForumAttachmentRelationshipColumns.AttachmentThumbnail,
			model.ForumAttachmentRelationshipColumns.AttachmentOrder,
			model.ForumAttachmentRelationshipColumns.AttachmentImageURL,
		}
		mediaList, _, listErr := l.svcCtx.ForumPost.GetMedia(l.ctx, model.M{
			"pageSize": pageSize,
			"orderBy":  model.ForumAttachmentRelationshipColumns.AttachmentOrder,
			"select":   strings.Join(subSelectCols, ","),
		}, -1, mediaFilterMap)
		if listErr != nil {
			return 0, listErr
		}

		idPhotoMap := make(map[uint64][]*MediaInfo)
		if len(mediaList) > 0 {
			for _, media := range mediaList {
				idPhotoMap[media.ObjectID] = append(idPhotoMap[media.ObjectID], &MediaInfo{
					Uid:       int64(media.AttachmentRelationshipID),
					Id:        int64(media.AttachmentID),
					Url:       media.AttachmentImageURL,
					Thumbnail: media.AttachmentThumbnail > 0,
					Order:     int32(media.AttachmentOrder),
				})
			}
		}

		perfumeMap, perfumeErr := l.getPerfumeMap(pids)
		if perfumeErr != nil {
			return 0, perfumeErr
		}

		var list []*PhotoInfo
		for _, post := range postList {
			if ps, exist := idPhotoMap[post.PostID]; exist {
				var parent *PerfumeInfo
				if perfumeMap != nil {
					if p, ok := perfumeMap[int64(post.ParentID)]; ok {
						parent = p
					}
				}
				list = append(list, &PhotoInfo{
					Id:       int64(post.PostID),
					ParentId: int64(post.ParentID),
					Parent:   parent,
					Photos:   ps,
				})
			}
		}

		photoPostItems, err := json.Marshal(list)
		if err != nil {
			log.Info(fmt.Sprintf("photoPostItems marshal err: %+v", err))
			return 0, err
		}

		var meta []*userclient.UserMeta
		meta = append(meta, &userclient.UserMeta{
			Id:    in.UserId,
			Key:   mqueuex.UserCacheForumPhotoCount,
			Value: strconv.FormatInt(count, 10),
		})
		meta = append(meta, &userclient.UserMeta{
			Id:    in.UserId,
			Key:   mqueuex.UserCacheForumPhoto,
			Value: string(photoPostItems),
		})
		_, err = l.svcCtx.UserRpc.BackendSetMemberMeta(l.ctx, &userclient.BackendSetMemberMetaReq{
			UserMeta: meta,
		})
		if err != nil {
			return 0, err
		}

		return int(count), nil
	}

	return 0, nil
}

func (l *DiagnoseLogic) diagnoseForumFeed(in *forum.DiagnoseReq) (int, error) {
	filterMap := make(map[string]map[string][]any)
	filterMap[model.ForumTopicColumns.ForumID] = map[string][]any{
		"moreThanOrEqualTo": []any{l.svcCtx.Config.Query.DefaultForumId},
	}
	filterMap[model.ForumTopicColumns.TopicStatus] = map[string][]any{
		"equalTo": []any{enumx.ObjectStatusAproved},
	}
	var pageSize int64 = 10
	selectCols := []string{
		model.ForumTopicColumns.TopicID,
		model.ForumTopicColumns.ForumID,
		model.ForumTopicColumns.TopicAuthorID,
		model.ForumTopicColumns.TopicAuthorNickname,
		model.ForumTopicColumns.Title,
		model.ForumTopicColumns.TopicDate,
		model.ForumTopicColumns.TopicModifiedDate,
		model.ForumTopicColumns.Sticky,
	}
	topicList, _, err := l.svcCtx.ForumTopic.GetList(l.ctx, model.M{
		"pageSize": pageSize,
		"orderBy":  model.ForumTopicColumns.TopicModifiedDate + " DESC",
		"select":   strings.Join(selectCols, ","),
	}, -1, filterMap)
	if err != nil {
		return 0, err
	}

	if len(topicList) > 0 {
		var ids []any // []model.ForumTopic.TopicID
		var aids []string
		for _, topic := range topicList {
			ids = append(ids, topic.TopicID)
			aids = append(aids, strconv.FormatInt(int64(topic.TopicAuthorID), 10))
		}

		mediaFilterMap := make(map[string]map[string][]any)
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"in": ids,
		}
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": []any{enumx.ObjectTypeTopic},
		}
		subSelectCols := []string{
			model.ForumAttachmentRelationshipColumns.ObjectID,
			model.ForumAttachmentRelationshipColumns.AttachmentID,
			model.ForumAttachmentRelationshipColumns.AttachmentImageURL,
		}
		mediaList, _, listErr := l.svcCtx.ForumPost.GetMedia(l.ctx, model.M{
			"orderBy": model.ForumAttachmentRelationshipColumns.AttachmentOrder,
			"select":  strings.Join(subSelectCols, ","),
		}, -1, mediaFilterMap)
		if listErr != nil {
			return 0, listErr
		}

		idMediaMap := make(map[uint64]*MediaInfo)
		if len(mediaList) > 0 {
			for _, media := range mediaList {
				if _, exist := idMediaMap[media.ObjectID]; !exist {
					idMediaMap[media.ObjectID] = &MediaInfo{
						Id:  int64(media.AttachmentID),
						Url: media.AttachmentImageURL,
					}
				}
			}
		}

		authorMap, authorErr := l.getAuthorMap(aids)
		if authorErr != nil {
			return 0, authorErr
		}

		var count int
		for _, topic := range topicList {
			author := &AuthorInfo{}
			if authorMap != nil {
				if a, exist := authorMap[int64(topic.TopicAuthorID)]; exist {
					author = a
				}
			}
			media := &MediaInfo{}
			if m, exist := idMediaMap[topic.TopicID]; exist {
				media = m
			}

			err = l.svcCtx.ForumUser.InsertFeed(l.ctx, &model.ForumFeed{
				ForumID:        topic.ForumID,
				TopicID:        topic.TopicID,
				AuthorID:       topic.TopicAuthorID,
				AuthorNickname: author.Nickname,
				AuthorAvatar:   author.Avatar,
				AuthorRankID:   uint8(author.Level),
				Excerpt:        topic.Title,
				ThumbnailID:    uint64(media.Id),
				ThumbnailURL:   media.Url,
				Status:         uint8(enumx.ObjectStatusAproved),
				Sticky:         topic.Sticky,
				CreatedAt:      topic.TopicDate,
				UpdatedAt:      topic.TopicModifiedDate,
			})
			if err != nil {
				return 0, err
			}

			count += 1
		}

		return count, nil
	}

	return 0, nil
}

func (l *DiagnoseLogic) getPerfumeMap(ids []string) (map[int64]*PerfumeInfo, error) {
	if len(ids) == 0 {
		return nil, nil
	}

	res, err := l.svcCtx.BlogRpc.BookList(l.ctx, &blogclient.BookListReq{
		Preload:   "blogBook:Id,Title,Slug;blogMedia:Id,Uid,Url,Thumbnail,Order;blogBookRelation:brand",
		EagerLoad: "blogBook:blogMedia,blogBookRelation",
		EntryIds:  strings.Join(ids, ","),
	})
	if err != nil {
		return nil, err
	}

	if len(res.Data) > 0 {
		resp := make(map[int64]*PerfumeInfo)
		for _, item := range res.Data {
			var media []*MediaInfo
			if len(item.Media) > 0 {
				for _, m := range item.Media {
					media = append(media, &MediaInfo{
						Uid:       m.Uid,
						Id:        m.Id,
						Url:       m.Url,
						Thumbnail: m.Thumbnail > 0,
						Order:     m.Order,
					})
				}
			}
			var brand []*PerfumeInfo
			if len(item.Relations) > 0 {
				for _, r := range item.Relations {
					if r.Section == "brand" {
						brand = append(brand, &PerfumeInfo{
							Id:    r.Id,
							Title: r.Title,
							Slug:  r.Slug,
						})
					}
				}
			}
			resp[item.Id] = &PerfumeInfo{
				Id:    item.Id,
				Title: item.Title,
				Slug:  item.Slug,
				Media: media,
				Brand: brand,
			}
		}
		return resp, nil
	}

	return nil, nil
}

func (l *DiagnoseLogic) getAuthorMap(ids []string) (map[int64]*AuthorInfo, error) {
	if len(ids) == 0 {
		return nil, nil
	}

	res, err := l.svcCtx.UserRpc.BackendMemberList(l.ctx, &userclient.BackendMemberListReq{
		MemberIds: strings.Join(ids, ","),
	})
	if err != nil {
		return nil, err
	}

	if len(res.List) > 0 {
		resp := make(map[int64]*AuthorInfo)
		for _, item := range res.List {
			resp[item.Id] = &AuthorInfo{
				Id:       item.Id,
				Nickname: item.Nickname,
				Avatar:   item.Avatar,
				Level:    item.Level,
			}
		}
		return resp, nil
	}

	return nil, nil
}

func getStatusText(status int32) (res string) {
	switch enumx.ObjectStatus(status) {
	case enumx.ObjectStatusAproved: // 审核通过
		res = "aproved"
	case enumx.ObjectStatusPending: // 待审核
		res = "pending"
	case enumx.ObjectStatusRejected: // 审核未通过
		res = "rejected"
	case enumx.ObjectStatusDeleted: // 用户已删除
		res = "deleted"
	case enumx.ObjectStatusCheckSuccess: // 待审核
		res = "pending"
	case enumx.ObjectStatusCheckFailed: // 待审核
		res = "rejected"
	}

	return
}

func (l *DiagnoseLogic) diagnoseUserCollect(in *forum.DiagnoseReq) (int, error) {
	var preload string
	var eagerLoad string
	preload = "blogBook:Id,Title,Slug;blogBookMeta:year,minProductGems,averageRating,popularity,season,gender"
	eagerLoad = "blogBook:blogBookMeta"
	res, err := l.svcCtx.BlogRpc.BookList(l.ctx, &blogclient.BookListReq{
		Preload:   preload,
		EagerLoad: eagerLoad,
		EntryIds:  "40046,40054,40057,40094,40101",
	})
	if err != nil {
		return 0, err
	}

	if len(res.Data) > 0 {
		platformId := int32(enumx.ThirdPartyPlatformWechatMini)
		now := time.Now()
		for _, item := range res.Data {
			log.Info(fmt.Sprintf("diagnoseUserCollect item.Meta: %d", len(item.Meta)))
			var year string
			var minProductGems string
			var averageRating string
			var popularity string
			var season string
			var gender string
			if len(item.Meta) > 0 {
				for _, m := range item.Meta {
					log.Info(fmt.Sprintf("diagnoseUserCollect Meta key: %s, value: %s", m.Key, m.Value))
					switch m.Key {
					case "year":
						year = m.Value
					case "minProductGems":
						minProductGems = m.Value
					case "averageRating":
						if f, err := strconv.ParseFloat(m.Value, 64); err == nil {
							averageRating = moneyx.FormatStar(f, 1)
						} else {
							log.Info(fmt.Sprintf("diagnoseUserCollect averageRating err: %+v", err))
						}
					case "popularity":
						popularity = m.Value
					case "season":
						season = m.Value
					case "gender":
						gender = m.Value
					}
				}
			}

			_, err = l.svcCtx.ForumUser.UpdateCollect(l.ctx, &model.ForumUserCollect{
				UserID:       uint64(in.UserId),
				PlatformID:   uint(platformId),
				ObjectID:     uint64(item.Id),
				ObjectType:   uint16(enumx.PostTypeKnowledgeBase),
				Status:       1,
				CreatedAt:    now,
				UpdatedAt:    now,
				SorterValue1: null.StringFrom(item.Slug),
				SorterValue2: null.StringFrom(year),
				SorterValue3: null.StringFrom(minProductGems),
				SorterValue4: null.StringFrom(averageRating),
				SorterValue5: null.StringFrom(popularity),
				FilterValue3: null.StringFrom(season),
				FilterValue5: null.StringFrom(gender),
			})
		}
	}

	return len(res.Data), nil
}
